﻿//=====================================================
//Copyright (C) 2016-2017 Fanjia
//All rights reserved
//CLR版 本:  4.0.30319.36315
//创建时间:  2017-04-27 14:54:48
//创 建 人:  康文艺
//======================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using WindowsFormsApplication1.Common;
using FanJiaCommon.Kits;
using Newtonsoft.Json;

namespace FanjiaHotelPlatform.utils.Kits
{
    public class WebRequestKit
    {

        private const string DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";

        #region CreateGetHttpResponse 创建GET方式的HTTP请求
        /// <summary>  
        /// 创建GET方式的HTTP请求  
        /// </summary>  
        /// <param name="url">请求的URL</param>  
        /// <param name="timeout">请求的超时时间</param>  
        /// <param name="userAgent">请求的客户端浏览器信息，可以为空</param>  
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>
        /// <param name="headers">头信息设置</param>
        /// <returns></returns>  
        public static HttpWebResponse CreateGetHttpResponse(string url, int? timeout, string userAgent, CookieCollection cookies, Dictionary<string, string> headers = null)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            var request = WebRequest.Create(url) as HttpWebRequest;
            if (request == null)
            {
                throw new NullReferenceException("HttpWebRequest");
            }
            request.Method = "GET";
            request.UserAgent = DefaultUserAgent;
            if (!string.IsNullOrEmpty(userAgent))
            {
                request.UserAgent = userAgent;
            }
            if (timeout.HasValue)
            {
                request.Timeout = timeout.Value;
            }
            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
            }
            if (headers != null)
            {
                foreach (var item in headers)
                    request.Headers.Add(item.Key, item.Value);
            }
            return request.GetResponse() as HttpWebResponse;
        }
        /// <summary>
        /// 创建一个Get请求对象
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="timeout">超时设置</param>
        /// <param name="userAgent">代理设置</param>
        /// <param name="cookies">请求cookies</param>
        /// <param name="headers">头信息设置</param>
        /// <returns></returns>
        public static HttpWebResponse CreateGetHttpsResponse(string url, int? timeout, string userAgent, CookieCollection cookies, Dictionary<string, string> headers = null)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            var request = default(HttpWebRequest);
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                request = WebRequest.Create(url) as HttpWebRequest;
                request.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                request = WebRequest.Create(url) as HttpWebRequest;
            }

            if (request == null)
            {
                throw new NullReferenceException("HttpWebRequest");
            }
            request.Method = "GET";
            request.UserAgent = DefaultUserAgent;
            if (!string.IsNullOrEmpty(userAgent))
            {
                request.UserAgent = userAgent;
            }
            if (timeout.HasValue)
            {
                request.Timeout = timeout.Value;
            }
            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
            }
            if (headers != null)
            {
                foreach (var item in headers)
                    request.Headers.Add(item.Key, item.Value);
            }
            return request.GetResponse() as HttpWebResponse;
        }
        #endregion

        #region CreatePostHttpResponse 创建POST方式的HTTP请求
        /// <summary>  
        /// 创建POST方式的HTTP请求  
        /// </summary>  
        /// <param name="url">请求的URL</param>  
        /// <param name="parameters">随同请求POST的参数名称及参数值字典</param>  
        /// <param name="timeout">请求的超时时间</param>  
        /// <param name="userAgent">请求的客户端浏览器信息，可以为空</param>  
        /// <param name="requestEncoding">发送HTTP请求时所用的编码</param>  
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>
        /// <param name="headers">头信息设置</param>
        /// <returns></returns>  
        public static HttpWebResponse CreatePostHttpResponse(string url, IDictionary<string, string> parameters, int? timeout, string userAgent
            , Encoding requestEncoding, CookieCollection cookies, Dictionary<string, string> headers = null)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            if (requestEncoding == null)
            {
                throw new ArgumentNullException("requestEncoding");
            }
            HttpWebRequest request;
            //如果是发送HTTPS请求  
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;
                request = WebRequest.Create(url) as HttpWebRequest;
                if (request == null)
                {
                    throw new NullReferenceException("HttpWebRequest");
                }
                request.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                request = WebRequest.Create(url) as HttpWebRequest;
            }
            if (request == null)
            {
                throw new NullReferenceException("HttpWebRequest");
            }
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            request.UserAgent = !string.IsNullOrEmpty(userAgent) ? userAgent : DefaultUserAgent;

            if (timeout.HasValue)
            {
                request.Timeout = timeout.Value;
            }
            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
            }

            if (headers != null)
            {
                foreach (var item in headers)
                    request.Headers.Add(item.Key, item.Value);
            }

            //如果需要POST数据  
            if (!(parameters == null || parameters.Count == 0))
            {
                var buffer = new StringBuilder();
                int i = 0;
                foreach (string key in parameters.Keys)
                {
                    if (i > 0)
                    {
                        buffer.AppendFormat("&{0}={1}", key, parameters[key]);
                    }
                    else
                    {
                        buffer.AppendFormat("{0}={1}", key, parameters[key]);
                    }
                    i++;
                }
                byte[] data = requestEncoding.GetBytes(buffer.ToString());
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
            }
            return request.GetResponse() as HttpWebResponse;
        }

        #endregion
        #region Post POST并返回字符串结果

        /// <summary>  
        /// POST并返回字符串结果
        /// </summary>  
        /// <param name="url">请求的URL</param>  
        /// <param name="parameters">随同请求POST的参数名称及参数值字典</param>  
        /// <param name="timeout">请求的超时时间</param>  
        /// <param name="userAgent">请求的客户端浏览器信息，可以为空</param>  
        /// <param name="requestEncoding">发送HTTP请求时所用的编码</param>  
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>
        /// <param name="headers">头信息设置</param>
        /// <returns></returns>  
        public static string Post(string url, IDictionary<string, string> parameters, int? timeout,
            string userAgent, Encoding requestEncoding, CookieCollection cookies, Dictionary<string, string> headers = null)
        {
            try
            {
                //XmlRequestKit.Post(requestUrl, dic, 20000, null, Encoding.UTF8, null);
                HttpWebResponse response = CreatePostHttpResponse(url, parameters, 100000, string.Empty, requestEncoding, cookies, headers);
                var stream = response.GetResponseStream();
                if (stream != null)
                {
                    using (stream)
                    using (var streamReader = new StreamReader(stream, requestEncoding))
                    {
                        return streamReader.ReadToEnd();
                    }
                }
                return string.Empty;
            }
            catch
            {
                return string.Empty;
            }
        }

        #endregion

        #region Get
        /// <summary>
        /// 简单的Get请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <returns></returns>
        public static string Get(string url)
        {
            string result = string.Empty;
            var uri = new Uri(url);
            try
            {
                var httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
                httpWebRequest.Method = "get";
                var response = (HttpWebResponse)httpWebRequest.GetResponse();
                using (Stream steam = response.GetResponseStream())
                {
                    if (steam != null)
                    {
                        using (var reader = new StreamReader(steam, Encoding.UTF8))
                        {
                            result = reader.ReadToEnd();
                            reader.Close();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                result += e.Message;
            }
            return result;
        }

        #endregion

        #region CheckValidationResult
        /// <summary>
        /// 请求证书设置
        /// </summary>
        /// <param name="sender">发送者</param>
        /// <param name="certificate">证书</param>
        /// <param name="chain">证书生成方式</param>
        /// <param name="errors">证书错误信息</param>
        /// <returns></returns>
        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受  
        }

        #endregion

        #region BindRequestXml

        /// <summary>
        /// 创建一个xml参数请求
        /// </summary>
        /// <param name="xmlString">xml字符串</param>
        /// <param name="parameter">一个对象</param>
        /// <returns></returns>
        public static string BindRequestXml(string xmlString, object parameter)
        {
            var propertiesBase = parameter.GetType().GetProperties();
            foreach (var propertyInfo in propertiesBase)
            {
                var value = propertyInfo.GetValue(parameter, null);
                var name = string.Format("{{{0}}}", propertyInfo.Name);
                xmlString = xmlString.Replace(name, value == null ? string.Empty : value.ToString());
            }
            return xmlString;
        }
        /// <summary>
        /// 发起xml请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="xmlParameters">xml参数</param>
        /// <param name="timeout">超时时间</param>
        /// <param name="userAgent">代理设置</param>
        /// <param name="requestEncoding">请求编码</param>
        /// <param name="cookies">cookies设置</param>
        /// <param name="headers">头信息设置</param>
        /// <returns></returns>
        public static HttpWebResponse CreateXmlPostHttpResponse(string url, string xmlParameters, int? timeout, string userAgent
            , Encoding requestEncoding, CookieCollection cookies, Dictionary<string, string> headers = null)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            if (requestEncoding == null)
            {
                throw new ArgumentNullException("requestEncoding");
            }
            HttpWebRequest request;
            //如果是发送HTTPS请求  
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;
                request = WebRequest.Create(url) as HttpWebRequest;
                if (request == null)
                {
                    throw new NullReferenceException("HttpWebRequest");
                }
                request.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                request = WebRequest.Create(url) as HttpWebRequest;
            }
            if (request == null)
            {
                throw new NullReferenceException("HttpWebRequest");
            }
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            request.UserAgent = !string.IsNullOrEmpty(userAgent) ? userAgent : DefaultUserAgent;

            if (timeout.HasValue)
            {
                request.Timeout = timeout.Value;
            }
            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
            }

            if (headers != null)
            {
                foreach (var item in headers)
                    request.Headers.Add(item.Key, item.Value);
            }

            //如果需要POST数据  
            if (!string.IsNullOrEmpty(xmlParameters))
            {
                byte[] data = requestEncoding.GetBytes(xmlParameters);
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
            }
            return request.GetResponse() as HttpWebResponse;
        }
        #endregion
        /// <summary>
        ///  发起一个json请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="json">json请求参数</param>
        /// <param name="timeout">超时时间</param>
        /// <param name="requestEncoding">请求编码</param>
        /// <returns></returns>
        public static string CreateJsonPostHttpRequest(string url, string json, int? timeout, Encoding requestEncoding)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            if (requestEncoding == null)
            {
                throw new ArgumentNullException("requestEncoding");
            }
            HttpWebRequest request;
            //如果是发送HTTPS请求  
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;
                request = WebRequest.Create(url) as HttpWebRequest;
                if (request == null)
                {
                    throw new NullReferenceException("HttpWebRequest");
                }
                request.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                request = WebRequest.Create(url) as HttpWebRequest;
            }
            if (request == null)
            {
                throw new NullReferenceException("HttpWebRequest");
            }

            request.Method = "POST";
            request.ContentType = "application/json";
            request.Accept = "application/json";
            request.UserAgent = DefaultUserAgent;
            request.ContentLength = Encoding.UTF8.GetByteCount(json);
            if (timeout.HasValue)
            {
                request.Timeout = timeout.Value;
            }

            try
            {
                LogHelper.WriteLog(json);//

                byte[] data = requestEncoding.GetBytes(json);
                using (Stream requestStream = request.GetRequestStream())
                {
                    requestStream.Write(data, 0, data.Length);
                }

                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                Stream responseStream = response.GetResponseStream();
                if (responseStream != null)
                {
                    using (responseStream)
                    using (var streamReader = new StreamReader(responseStream, requestEncoding))
                    {
                        var rst = streamReader.ReadToEnd();
                        LogHelper.WriteLog(rst);//
                        return rst;
                    }
                }
                return string.Empty;
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog(ex.Message, ex);//
                throw ex;
            }
        }
        /// <summary>
        /// 异步远程请求
        /// </summary>
        /// <typeparam name="T1">返回的对象</typeparam>
        /// <typeparam name="T2">传入json对象类型</typeparam>
        /// <param name="url">url地址</param>
        /// <param name="json">json对象</param>
        /// <param name="timeout">超时时间</param>
        /// <param name="requestEncoding">编码类型</param>
        /// <returns></returns>
        public static async Task<T1> CreateJsonPostHttpRequestAsync<T1, T2>(string url, T2 json, int? timeout, Encoding requestEncoding) where T1 : class, new()
        {
            var client = FjPushHttpClient.Instance;
            var request = new HttpRequestMessage(HttpMethod.Post, url)
            {
                Content = new StringContent(JsonConvert.SerializeObject(json), requestEncoding, "application/json")
            };
            var response = await client.SendAsync(request);
            var result=await response.Content.ReadAsStringAsync();
            return JsonKit.DeserializeJsonToObject<T1>(result);
        }

        /// <summary>
        /// 以异步操作的方式将 POST 请求发送到指定的地址，该请求中包含序列化为 JSON 的给定值
        /// </summary>
        /// <typeparam name="TOutput">输出类型</typeparam>
        /// <param name="requestUri">请求地址</param>
        /// <param name="value">输入参数</param>
        /// <returns>输出数据</returns>
        public static async Task<TOutput> PostAsJsonAsync<TOutput>(string requestUri, object value)
            where TOutput : class
        {
            var content = JsonConvert.SerializeObject(value, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
            var request = new HttpRequestMessage(HttpMethod.Post, requestUri)
            {
                Content = new StringContent(content, Encoding.UTF8, "application/json")
            };
            var response = await FjPushHttpClient.Instance.SendAsync(request);
            var json = await response.Content.ReadAsStringAsync();
            return JsonKit.DeserializeJsonToObject<TOutput>(json);
        }
        /// <summary>
        /// 以异步操作的方式将 POST 请求发送到指定的地址，该请求中包含序列化为 JSON 的给定值
        /// </summary>
        /// <typeparam name="TOutput">输出类型</typeparam>
        /// <param name="requestUri">请求地址</param>
        /// <param name="value">输入参数</param>
        /// <returns>输出数据</returns>
        public static async Task<TOutput> PostAsJsonByGZipStreamAsync<TOutput>(string requestUri, object value)
            where TOutput : class
        {
            var content = JsonConvert.SerializeObject(value, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
            var request = new HttpRequestMessage(HttpMethod.Post, requestUri)
            {
                Content = new StringContent(content, Encoding.UTF8, "application/json")
            };
            var response = await FjPushHttpClient.Instance.SendAsync(request);
            var resultStream = await response.Content.ReadAsStreamAsync();
            GZipStream gzip = new GZipStream(resultStream, CompressionMode.Decompress);//解压缩
            using (StreamReader reader = new StreamReader(gzip, Encoding.UTF8))
            {
                var result = reader.ReadToEnd();
                return JsonKit.DeserializeJsonToObject<TOutput>(result);
            }
        }
        /// <summary>
        /// 以异步操作的方式将 POST 请求发送到指定的地址，该请求中包含序列化为 JSON 的给定值
        /// </summary>
        /// <typeparam name="TOutput">输出类型</typeparam>
        /// <param name="requestUri">请求地址</param>
        /// <param name="value">输入参数</param>
        /// <returns>输出数据</returns>
        public static async Task<string> PostAsStringAsync(string requestUri, object value)
        {
            var content = JsonConvert.SerializeObject(value);
            var request = new HttpRequestMessage(HttpMethod.Post, requestUri)
            {
                Content = new StringContent(content, Encoding.UTF8, "application/json")
            };
            var response = await FjPushHttpClient.Instance.SendAsync(request);
            var result = await response.Content.ReadAsStringAsync();
            return result;
        }
        /// <summary>
        /// 以异步操作的方式将 POST 请求发送到指定的地址，该请求中包含序列化为 JSON 的给定值
        /// </summary>
        /// <typeparam name="TOutput">输出类型</typeparam>
        /// <param name="requestUri">请求地址</param>
        /// <param name="value">输入参数</param>
        /// <returns>输出数据</returns>
        public static async Task<string> PostAsStringByGZipStreamAsync(string requestUri, object value)
        {
            var content = JsonConvert.SerializeObject(value, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
            //var content = JsonConvert.SerializeObject(value);
            var request = new HttpRequestMessage(HttpMethod.Post, requestUri)
            {
                Content = new StringContent(content, Encoding.UTF8, "application/json")
            };
            var response = await FjPushHttpClient.Instance.SendAsync(request);
            var resultStream = await response.Content.ReadAsStreamAsync();

            GZipStream gzip = new GZipStream(resultStream, CompressionMode.Decompress);//解压缩
            using (StreamReader reader = new StreamReader(gzip, Encoding.UTF8))
            {
                var result = reader.ReadToEnd();
                return result;
            }
        }
    }
    /// <summary>
    /// 为泛嘉PUSH数据时使用的HttpClient实例，地址需要自行指定（为BaseAddress指定路径参数），数据PUSH格式为application/json，提高使用率本辅助类为单例创建
    /// </summary>
    public sealed class FjPushHttpClient : HttpClient
    {
        private FjPushHttpClient() { }

        private FjPushHttpClient(HttpClientHandler handle)
            : base(handle)
        {

        }

        public static FjPushHttpClient Instance
        {
            get { return FJHttpClient.instance; }
        }

        private class FJHttpClient
        {
            internal static readonly FjPushHttpClient instance = null;
            static FJHttpClient()
            {
                var handler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.None };
                instance = new FjPushHttpClient(handler);

                instance.BaseAddress = new Uri("http://192.168.1.123/");
                instance.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            }
        }
    }

    /// <summary>
    /// 为泛嘉PUSH数据时使用的HttpClient实例，地址需要自行指定（为BaseAddress指定路径参数），数据PUSH格式为text/plan，提高使用率本辅助类为单例创建
    /// </summary>
    public sealed class FjPushHttpClientForText : HttpClient
    {
        private FjPushHttpClientForText() { }

        private FjPushHttpClientForText(HttpClientHandler handle)
            : base(handle)
        {

        }

        public static FjPushHttpClientForText Instance
        {
            get { return FJHttpClient.instance; }
        }

        private class FJHttpClient
        {
            internal static readonly FjPushHttpClientForText instance = null;
            static FJHttpClient()
            {
                var handler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.None };
                instance = new FjPushHttpClientForText(handler);

                instance.BaseAddress = new Uri("http://192.168.1.123/");
                instance.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
            }
        }
    }
}
